
package com.hlkj.pay.app.merchant.ext.impl.fuyou;
/*
 * Hlpay-Plus aggregate payment system.
 * Copyright (c) 2024-2025 Hlpay Team Copyright has the right of final interpretation.
 */

import java.math.BigDecimal;
import java.net.URLEncoder;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;

import org.springframework.stereotype.Repository;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import com.hlkj.framework.common.pojo.CommonResult;
import com.hlkj.framework.common.util.json.JsonUtils;
import com.hlkj.framework.extension.annotation.Extension;
import com.hlkj.pay.app.merchant.ext.ChannelMerchantSettleExtPt;
import com.hlkj.pay.app.merchant.ext.MerchantExtConstant;
import com.hlkj.pay.app.merchant.ext.dto.settle.ChannelMerchantAccessSettleContext;
import com.hlkj.pay.app.merchant.ext.impl.fuyou.constant.FuYouConstant;
import com.hlkj.pay.app.merchant.ext.impl.fuyou.dto.*;
import com.hlkj.pay.app.merchant.ext.impl.fuyou.handler.FuYouMerchantCommonParamsHandle;
import com.hlkj.pay.app.merchant.ext.impl.fuyou.utils.HttpUtils;
import com.hlkj.pay.app.merchant.ext.impl.fuyou.utils.SignUtils;
import com.hlkj.pay.dto.merchant.access.MerchantAccessBalanceDto;
import com.hlkj.pay.dto.order.notify.OrderSettleNotifyDto;
import com.hlkj.pay.enums.MerchantEnum;
import com.hlkj.pay.infrastructure.model.merchant.MerchantAccessInfoDO;
import com.hlkj.pay.infrastructure.model.merchant.settle.MerchantAccessSettleOrderDO;
import com.hlkj.pay.infrastructure.model.order.OrderSettleDO;
import com.hlkj.pay.infrastructure.model.pay.ProviderChannelConfigDO;
import com.hlkj.pay.util.DateUtils;
import com.hlkj.pay.util.MerchantUtils;

import cn.hutool.core.bean.BeanUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;

/**
 * @author HlpayTeam
 * @date 2024/12/29 17:40
 */
@Slf4j
@Repository
@RequiredArgsConstructor
@Extension(bizId = MerchantExtConstant.CHANNEL_FU_YOU)
public class FuYouMerchantSettleExtPt extends FuYouMerchantCommonParamsHandle implements ChannelMerchantSettleExtPt {

    @Override
    public void queryAccessBalance(ChannelMerchantAccessSettleContext merchantAccessAuthQueryContext) {
        CommonResult<FuYouConfig> fuYouConfigCommonResult = channelConfig(merchantAccessAuthQueryContext.getProviderChannelConfig());
        // 配置转换
        if (!fuYouConfigCommonResult.isSuccess()) {
            merchantAccessAuthQueryContext.setRemark(fuYouConfigCommonResult.getMsg());
            merchantAccessAuthQueryContext.setProcessStatus(Boolean.FALSE);
            return;
        }
        FuYouConfig fuYouConfig = fuYouConfigCommonResult.getData();
        // 1. 数据初始化
        MerchantAccessInfoDO merchantAccessInfo = merchantAccessAuthQueryContext.getMerchantAccessInfo();
        try {
            Map<String, Object> params = new HashMap<>();
            params.put("ins_cd", fuYouConfig.getInsCd());
            params.put("mchnt_cd", merchantAccessInfo.getSubMchId());
            params.put("random_str", System.currentTimeMillis() + "");
            params.put("sign", SignUtils.getPaySign(params, fuYouConfig));
            log.info("富友 查询商户余额 参数:{}", JsonUtils.toJsonString(params));
            String mapToXml = SignUtils.convertMapToXml(params);
            log.info("富友 查询商户余额 xml参数:{}", mapToXml);
            Map<String, String> requestParams = new HashMap<>();
            mapToXml = URLEncoder.encode(mapToXml, FuYouConstant.charset);
            requestParams.put("req", mapToXml);
            String url = domainSettle(merchantAccessAuthQueryContext.isTest()) + FuYouConstant.SETTLE_BALANCE_QUERY;
            log.info("富友 查询商户余额 最终参数:{}", JsonUtils.toJsonString(requestParams));
            String response = HttpUtils.post(url, requestParams);
            // 响应报文验签
            // FuYouPayOrderResultDto fuYouPayOrderResultDto =
            // SignUtils.xmlToObject(response, FuYouPayOrderResultDto.class);
            Map<String, Object> stringObjectMap = SignUtils.xmlToObject(response);
            FuYouSettleBalanceQueryResultDto fuYouPayOrderResultDto = BeanUtil.mapToBean(stringObjectMap, FuYouSettleBalanceQueryResultDto.class, true);
            log.info("富友 查询商户余额 返回参数:{}", JsonUtils.toJsonString(fuYouPayOrderResultDto));
            MerchantAccessBalanceDto merchantAccessBalanceDto = new MerchantAccessBalanceDto();
            merchantAccessAuthQueryContext.setMerchantAccessBalanceDto(merchantAccessBalanceDto);
            if (fuYouPayOrderResultDto.success()) {
                // merchantAccessBalanceDto.setAmountToBeSettled(fuYouPayOrderResultDto.getNot_settle_amt());
                if (StringUtils.hasText(fuYouPayOrderResultDto.getReserved_book_balance())) {
                    BigDecimal bigDecimal = new BigDecimal(fuYouPayOrderResultDto.getNot_settle_amt());
                    merchantAccessBalanceDto.setAmountToBeSettled(MerchantUtils.bigDecimalToString2(MerchantUtils.fenToYuan(bigDecimal.intValue())));
                }
                else {
                    merchantAccessBalanceDto.setAmountToBeSettled("0.00");
                }
                if (StringUtils.hasText(fuYouPayOrderResultDto.getReserved_book_balance())) {
                    BigDecimal bigDecimal = new BigDecimal(fuYouPayOrderResultDto.getReserved_book_balance());
                    merchantAccessBalanceDto.setBalance(MerchantUtils.bigDecimalToString2(MerchantUtils.fenToYuan(bigDecimal.intValue())));
                }
                else {
                    merchantAccessBalanceDto.setAmountToBeSettled("0.00");
                }
            }
            else {
                String respDesc = fuYouPayOrderResultDto.getErr_code_des();
                merchantAccessAuthQueryContext.setProcessStatus(Boolean.FALSE);
                if (StringUtils.hasText(respDesc)) {
                    merchantAccessAuthQueryContext.setRemark(respDesc);
                }
                else {
                    merchantAccessAuthQueryContext.setRemark("富友 商户余额查询 返回错误信息为空,错误码为:" + fuYouPayOrderResultDto.getErr_code());
                }
            }
        }
        catch (Exception e) {
            e.printStackTrace();
            log.error("富友 商户余额查询 请求失败,失败信息 message: {}", e.getMessage());
            merchantAccessAuthQueryContext.setRemark("富友 商户余额查询 请求失败,失败信息" + e.getMessage());
            merchantAccessAuthQueryContext.setProcessStatus(Boolean.FALSE);
        }
    }

    @Override
    public void submitAccessSettle(ChannelMerchantAccessSettleContext channelMerchantAccessSettleContext) {
        CommonResult<FuYouConfig> commonResult = channelConfig(channelMerchantAccessSettleContext.getProviderChannelConfig());
        FuYouConfig fuYouConfig = commonResult.getData();
        OrderSettleDO orderSettleDO = channelMerchantAccessSettleContext.getOrderSettleDO();
        MerchantAccessInfoDO merchantAccessInfo = channelMerchantAccessSettleContext.getMerchantAccessInfo();
        try {
            Map<String, Object> params = new HashMap<>();
            params.put("ins_cd", fuYouConfig.getInsCd());
            params.put("mchnt_cd", merchantAccessInfo.getSubMchId());
            params.put("random_str", System.currentTimeMillis() + "");
            params.put("amt", MerchantUtils.YuanToFen(orderSettleDO.getAmount()));
            params.put("reserved_busi_type", "1");
            params.put("sign", SignUtils.getPaySign(params, fuYouConfig));
            log.info("富友 查询手续费 参数:{}", JsonUtils.toJsonString(params));
            String mapToXml = SignUtils.convertMapToXml(params);
            log.info("富友 查询手续费 xml参数:{}", mapToXml);
            Map<String, String> requestParams = new HashMap<>();
            mapToXml = URLEncoder.encode(mapToXml, FuYouConstant.charset);
            requestParams.put("req", mapToXml);
            String url = domainSettle(channelMerchantAccessSettleContext.isTest()) + FuYouConstant.SETTLE_QUERY_FEE;
            log.info("富友 查询手续费 最终参数:{}", JsonUtils.toJsonString(requestParams));
            String response = HttpUtils.post(url, requestParams);
            Map<String, Object> stringObjectMap = SignUtils.xmlToObject(response);
            FuYouSettleFeeQueryResultDto fuYouPayOrderResultDto = BeanUtil.mapToBean(stringObjectMap, FuYouSettleFeeQueryResultDto.class, true);
            log.info("富友 查询手续费 返回参数:{}", JsonUtils.toJsonString(fuYouPayOrderResultDto));
            MerchantAccessSettleOrderDO updatePayOrderDO = new MerchantAccessSettleOrderDO();
            if (fuYouPayOrderResultDto.success()) {
                params.put("random_str", System.currentTimeMillis() + "");
                params.remove("reserved_busi_type");
                params.put("txn_type", 2);
                // params.put("fee_amt", fuYouPayOrderResultDto.getFee_amt());
                params.put("fee_amt", new BigDecimal(fuYouPayOrderResultDto.getFee_amt()).intValue());
                params.put("reserved_postscript", orderSettleDO.getRemark());
                params.put("reserved_order_no", orderSettleDO.getPayOrderNo());
                params.put("sign", SignUtils.getPaySign(params, fuYouConfig));
                log.info("富友 提交结算订单 参数:{}", JsonUtils.toJsonString(params));
                mapToXml = SignUtils.convertMapToXml(params);
                log.info("富友 提交结算订单 xml参数:{}", mapToXml);
                requestParams = new HashMap<>();
                mapToXml = URLEncoder.encode(mapToXml, FuYouConstant.charset);
                requestParams.put("req", mapToXml);
                url = domainSettle(channelMerchantAccessSettleContext.isTest()) + FuYouConstant.SETTLE_SUBMIT;
                log.info("富友 提交结算订单 最终参数:{}", JsonUtils.toJsonString(requestParams));
                response = HttpUtils.post(url, requestParams);
                stringObjectMap = SignUtils.xmlToObject(response);
                FuYouSettleSubmitResultDto fuYouSettleSubmitResultDto = BeanUtil.mapToBean(stringObjectMap, FuYouSettleSubmitResultDto.class, true);
                log.info("富友 提交结算订单 返回参数:{}", JsonUtils.toJsonString(fuYouSettleSubmitResultDto));
                if (fuYouSettleSubmitResultDto.success()) {
                    updatePayOrderDO.setOrderStatus(MerchantEnum.MERCHANT_ACCESS_AMOUNT_STATUS.DOING.getCode());
                    updatePayOrderDO.setSettleFee(MerchantUtils.fenToYuan(new BigDecimal(fuYouPayOrderResultDto.getFee_amt()).intValue()));
                }
                else {
                    String respDesc = fuYouSettleSubmitResultDto.getErr_code_des();
                    updatePayOrderDO.setOrderStatus(MerchantEnum.MERCHANT_ACCESS_AMOUNT_STATUS.FAIL.getCode());
                    if (StringUtils.hasText(respDesc)) {
                        updatePayOrderDO.setRemark(respDesc);
                    }
                    else {
                        updatePayOrderDO.setRemark("富友提交结算返回错误信息为空,错误码为:" + fuYouSettleSubmitResultDto.getErr_code());
                    }
                    channelMerchantAccessSettleContext.setRemark(updatePayOrderDO.getRemark());
                    channelMerchantAccessSettleContext.setProcessStatus(false);
                }
            }
            else {
                String respDesc = fuYouPayOrderResultDto.getErr_code_des();
                updatePayOrderDO.setOrderStatus(MerchantEnum.MERCHANT_ACCESS_AMOUNT_STATUS.FAIL.getCode());
                if (StringUtils.hasText(respDesc)) {
                    updatePayOrderDO.setRemark(respDesc);
                }
                else {
                    updatePayOrderDO.setRemark("富友提交结算返回错误信息为空,错误码为:" + fuYouPayOrderResultDto.getErr_code());
                }
                channelMerchantAccessSettleContext.setRemark(updatePayOrderDO.getRemark());
                channelMerchantAccessSettleContext.setProcessStatus(false);
            }
        }
        catch (Exception e) {
            e.printStackTrace();
            log.error("富友提交结算请求失败 message:{}", e.getMessage(), e);
            channelMerchantAccessSettleContext.setRemark("富友提交结算请求失败,失败信息" + e.getMessage());
            channelMerchantAccessSettleContext.setProcessStatus(Boolean.FALSE);
        }
    }

    @Override
    public void queryAccessSettle(ChannelMerchantAccessSettleContext channelMerchantAccessSettleContext) {
        CommonResult<FuYouConfig> commonResult = channelConfig(channelMerchantAccessSettleContext.getProviderChannelConfig());
        FuYouConfig fuYouConfig = commonResult.getData();
        OrderSettleDO orderSettleDO = channelMerchantAccessSettleContext.getOrderSettleDO();
        MerchantAccessInfoDO merchantAccessInfo = channelMerchantAccessSettleContext.getMerchantAccessInfo();
        try {
            Map<String, Object> params = new HashMap<>();
            params.put("ins_cd", fuYouConfig.getInsCd());
            params.put("mchnt_cd", merchantAccessInfo.getSubMchId());
            params.put("mchnt_order_no", "0");
            params.put("random_str", System.currentTimeMillis() + "");
            params.put("date", DateUtils.dateToString(orderSettleDO.getCreateTime(), "yyyyMMdd"));
            params.put("start_index", "1");
            params.put("end_index", "1");
            params.put("withdraw_type", "1");
            params.put("fy_trace_no", "");
            params.put("reserved_order_no", orderSettleDO.getPayOrderNo());
            params.put("sign", SignUtils.getPaySign(params, fuYouConfig));
            log.info("富友 查询结算详情 参数:{}", JsonUtils.toJsonString(params));
            String mapToXml = SignUtils.convertMapToXml(params);
            log.info("富友 查询结算详情 xml参数:{}", mapToXml);
            Map<String, String> requestParams = new HashMap<>();
            mapToXml = URLEncoder.encode(mapToXml, FuYouConstant.charset);
            requestParams.put("req", mapToXml);
            String url = domainSettle(channelMerchantAccessSettleContext.isTest()) + FuYouConstant.SETTLE_QUERY;
            log.info("富友 查询结算详情 最终参数:{}", JsonUtils.toJsonString(requestParams));
            String response = HttpUtils.post(url, requestParams);
            Map<String, Object> stringObjectMap = SignUtils.xmlToObject(response);
            FuYouSettleQueryResultDto fuYouPayOrderResultDto = BeanUtil.mapToBean(stringObjectMap, FuYouSettleQueryResultDto.class, true);
            log.info("富友 查询结算详情 返回参数:{}", JsonUtils.toJsonString(fuYouPayOrderResultDto));
            OrderSettleDO updatePayOrderDO = new OrderSettleDO();
            channelMerchantAccessSettleContext.setUpdateAccessAmountOrderDO(updatePayOrderDO);
            if (fuYouPayOrderResultDto.success()) {
                updatePayOrderDO.setOrderStatus(MerchantEnum.MERCHANT_ACCESS_AMOUNT_STATUS.DOING.getCode());
                List<FuYouSettleQueryResultDto.FuYouSettleQueryDetail> txnList = fuYouPayOrderResultDto.getTxnList();
                if (CollectionUtils.isEmpty(txnList)) {
                    updatePayOrderDO.setOrderStatus(MerchantEnum.MERCHANT_ACCESS_AMOUNT_STATUS.DOING.getCode());
                }
                else {
                    FuYouSettleQueryResultDto.FuYouSettleQueryDetail settleRecord = txnList.get(0);
                    if (settleRecord != null) {
                        // 1：成功
                        // 2：超时 / 已受理，交易结果稍后查询
                        // 3：失败
                        switch (settleRecord.getPay_st()) {
                            case "1":
                                updatePayOrderDO.setOrderStatus(MerchantEnum.MERCHANT_ACCESS_AMOUNT_STATUS.SUCCESS.getCode());
                                break;
                            case "2":
                                updatePayOrderDO.setOrderStatus(MerchantEnum.MERCHANT_ACCESS_AMOUNT_STATUS.DOING.getCode());
                                break;
                            case "3":
                                updatePayOrderDO.setOrderStatus(MerchantEnum.MERCHANT_ACCESS_AMOUNT_STATUS.FAIL.getCode());
                                break;
                            default:
                                break;
                        }
                        updatePayOrderDO.setRemark(settleRecord.getPay_st_desc());
                        if (StringUtils.hasText(settleRecord.getTxn_fee_amt())) {
                            updatePayOrderDO.setSettleFee(MerchantUtils.fenToYuan(new BigDecimal(settleRecord.getTxn_fee_amt()).intValue()));
                        }
                        if (StringUtils.hasText(settleRecord.getKbps_src_settle_dt())) {
                            try {
                                updatePayOrderDO.setSuccessTime(DateUtils.shanghaiLocalDate(settleRecord.getKbps_src_settle_dt(), "yyyyMMdd"));
                            }
                            catch (Exception e) {
                                log.error("富友 查询结算详情 时间格式化错误 dateTime:{},message:{}", settleRecord.getKbps_src_settle_dt(), e.getMessage());
                            }
                        }
                        if (StringUtils.hasText(settleRecord.getTxn_fee_amt())) {
                            updatePayOrderDO.setSettleFee(MerchantUtils.stringToBigDecimal(settleRecord.getTxn_fee_amt()));
                        }
                    }
                }
            }
            else {
                String respDesc = fuYouPayOrderResultDto.getErr_code_des();
                updatePayOrderDO.setOrderStatus(MerchantEnum.MERCHANT_ACCESS_AMOUNT_STATUS.FAIL.getCode());
                if (StringUtils.hasText(respDesc)) {
                    updatePayOrderDO.setRemark(respDesc);
                }
                else {
                    updatePayOrderDO.setRemark("富友结算查询返回错误信息为空,错误码为:" + fuYouPayOrderResultDto.getErr_code());
                }
            }
        }
        catch (Exception e) {
            e.printStackTrace();
            log.error("富友结算查询请求失败 message:{}", e.getMessage(), e);
            channelMerchantAccessSettleContext.setRemark("富友结算查询请求失败,失败信息" + e.getMessage());
            channelMerchantAccessSettleContext.setProcessStatus(Boolean.FALSE);
        }
    }

    @Override
    public CommonResult<OrderSettleNotifyDto> orderStatusParse(HttpServletRequest request, ProviderChannelConfigDO providerChannelConfigDO) {
        return CommonResult.success();
    }
}
